#include "stdafx.h"
#include "EnemyController.h"

#include "../d3d/d3dUtility.h"
#include "../Framework/ContentManager.h"
#include "../Framework/Toolkit.h"

namespace MyGame {

EnemyController::EnemyController(Game* game) : DrawableGameComponent(game) {
    this->bullets = new list<Bullet*>();
    this->enemies = new list<Enemy*>();
    this->missiles = new list<Missile*>();
    this->terrain = NULL;
    this->spawnTimer = 1;
}

EnemyController::~EnemyController(void) {
}

list<Bullet*>* EnemyController::GetBullets() const {
    return this->bullets;
}

list<Enemy*>* EnemyController::GetEnemies() const {
    return this->enemies;
}

list<Missile*>* EnemyController::GetMissiles() const {
    return this->missiles;
}

Player* EnemyController::GetPlayer() const {
    return this->player;
}

void EnemyController::SetPlayer(Player* val) {
    this->player = val;
}

Terrain* EnemyController::GetTerrain() const {
    return this->terrain;
}

void EnemyController::SetTerrain(Terrain* val) {
    this->terrain = val;
}

void EnemyController::Draw(FLOAT timeDelta) {
    for (list<Enemy*>::const_iterator it = this->enemies->begin(); it != this->enemies->end(); ++it) {
        if ((*it)->GetVisible()) {
            (*it)->Draw(timeDelta);
        }
    }

    for (list<Missile*>::const_iterator it = this->missiles->begin(); it != this->missiles->end(); ++it) {
        if ((*it)->GetVisible()) {
            (*it)->Draw(timeDelta);
        }
    }
}


void EnemyController::Initialize() {
    for (list<Enemy*>::const_iterator it = this->enemies->begin(); it != this->enemies->end(); ++it) {
        (*it)->Initialize();
    }

    for (list<Missile*>::const_iterator it = this->missiles->begin(); it != this->missiles->end(); ++it) {
        (*it)->Initialize();
    }
}

void EnemyController::LoadContent() {
    for (list<Enemy*>::const_iterator it = this->enemies->begin(); it != this->enemies->end(); ++it) {
        (*it)->LoadContent();
    }

    for (list<Missile*>::const_iterator it = this->missiles->begin(); it != this->missiles->end(); ++it) {
        (*it)->LoadContent();
    }
}

void EnemyController::UnloadContent() {
    for (list<Enemy*>::const_iterator it = this->enemies->begin(); it != this->enemies->end(); ++it) {
        (*it)->UnloadContent();
    }

    for (list<Missile*>::const_iterator it = this->missiles->begin(); it != this->missiles->end(); ++it) {
        (*it)->UnloadContent();
    }
}

void EnemyController::Update(FLOAT timeDelta) {
    if (this->player->GetState() == FLYINGSTATE_ALIVE) {
        if (this->enemies->size() < 10) {
            if (this->spawnTimer > 0) {
                this->spawnTimer -= timeDelta;
            } else {
                this->spawnTimer = 1;
                int team = Toolkit::RandomInt(1, 2);
                for (int i = 0; i < team; ++i) {
                    FLOAT x = (FLOAT)Toolkit::RandomFloat(-15, 15);
                    int n = Toolkit::RandomInt(3, 5);
                    for (int j = 0; j < n; ++j) {
                        Enemy* enemy = new Enemy(this->GetGame());
                        enemy->SetPlayer(this->player);
                        enemy->SetPosition(D3DXVECTOR3(x + j * 2, this->player->GetPosition().y, this->player->GetPosition().z + 100));
                        enemy->Initialize();
                        enemy->LoadContent();
                        this->enemies->push_back(enemy);
                    }
                }
            }
        }
    }

    this->UpdateEnemies(timeDelta);
    this->UpdateBullets(timeDelta);
    this->UpdateMissiles(timeDelta);
}

void EnemyController::UpdateBullets(FLOAT timeDelta) {
    list<Bullet*>::const_iterator bulletIt = this->bullets->begin();
    while (bulletIt != this->bullets->end()) {
        Bullet* bullet = *bulletIt;
        if (!bullet->IsAlive()) {
            bulletIt = this->bullets->erase(bulletIt);
            d3d::Delete(bullet);
        } else {
            bullet->Update(timeDelta);
            bool hit = false;
            D3DXVECTOR3 bPos = bullet->GetPosition();
            for (list<Enemy*>::const_iterator it = this->enemies->begin(); it != this->enemies->end(); ++it) {
                Enemy* enemy = *it;
                if (enemy->GetState() != FLYINGSTATE_ALIVE) {
                    continue;
                }

                D3DXVECTOR3 mPos = bullet->GetPosition();
                D3DXVECTOR3 mpPos = bullet->GetPrevPosition();
                d3d::BoundingSphere* sphere = enemy->GetBoundingSphere();
                if (Toolkit::CheckLineSphere(*sphere, mpPos, mPos)) {
                    enemy->InflictDamage(1);
                    this->player->SetScore(this->player->GetScore() + 1);
                    hit = true;
                    break;
                }
            }

            if (hit) {
                bulletIt = this->bullets->erase(bulletIt);
                d3d::Delete(bullet);
            } else {
                ++bulletIt;
            }
        }
    }
}

void EnemyController::UpdateEnemies(FLOAT timeDelta) {
    D3DXVECTOR3 playerPos = this->player->GetPosition();
    D3DXVECTOR3 playerPrevPos = this->player->GetPrevPosition();
    list<Enemy*>::const_iterator enemyIt = this->enemies->begin();
    while (enemyIt != this->enemies->end()) {
        Enemy* enemy = *enemyIt;
        if (enemy->GetState() == FLYINGSTATE_DEAD || enemy->GetPosition().z < this->player->GetPosition().z - 5) {
            enemyIt = this->enemies->erase(enemyIt);
            Missile* incomingMissile = enemy->GetIncomigMissile();
            if (incomingMissile != NULL) {
                incomingMissile->SetTarget(NULL);
            }

            d3d::Delete(enemy);
        } else {
            enemy->Update(timeDelta);
            if (enemy->GetState() == FLYINGSTATE_ALIVE) {
                d3d::BoundingBox* box = enemy->GetBoundingBox();
                D3DXVECTOR3 hit;
                if (Toolkit::CheckLineBox(*box, playerPrevPos, playerPos, hit)) {
                    this->player->InflictDamage(1);
                    enemy->InflictDamage(1);
                } else {
                    D3DXVECTOR3 pos = enemy->GetPosition();
                    FLOAT surfaceHeight = this->terrain->GetHeightFromSurface(D3DXVECTOR3(pos.x, 0, pos.z));
                    if (surfaceHeight > 2 && surfaceHeight + 1> pos.y) {
                        pos.y = surfaceHeight + 1;
                    }

                    enemy->SetPosition(pos);
                }
            }

            ++enemyIt;
        }
    }
}

void EnemyController::UpdateMissiles(FLOAT timeDelta) {
    list<Missile*>::const_iterator missileIt = this->missiles->begin();
    while (missileIt != this->missiles->end()) {
        Missile* missile = *missileIt;
        Jet* target = missile->GetTarget();
        if (target == NULL || missile->GetState() == FLYINGSTATE_DEAD || (target == this->player && missile->GetPosition().z < target->GetPosition().z - 1)) {
            missileIt = this->missiles->erase(missileIt);
            d3d::Delete(missile);
        } else {
            missile->Update(timeDelta);
            if (missile->GetState() == FLYINGSTATE_ALIVE) {
                D3DXVECTOR3 mPos = missile->GetPosition();
                D3DXVECTOR3 mpPos = missile->GetPrevPosition();
                d3d::BoundingBox* box = target->GetBoundingBox();
                D3DXVECTOR3 hit;
                if (Toolkit::CheckLineBox(*box, mpPos, mPos, hit)) {
                    target->InflictDamage(1);
                    missile->Explode();
                    if (target != this->player) {
                        this->player->SetScore(this->player->GetScore() + 1);
                    }
                }
            }

            ++missileIt;
        }
    }
}


}
